import { Languages, strMapLanguages } from "../common/Languages";
import { ConfigurationEnum, configurationUtil } from "../utils/ConfigurationUtil";
import { commands, Disposable, window } from "vscode";
import { QuestionData } from "../apis/get-question-data";
import * as fs from "fs-extra";
import * as path from "path";
import { LanguageServiceProviderAbstract } from "../languages/LanguageServiceProviderAbstract";
import { ERRORS } from "../common/Errors";

/**
 * 语言环境服务
 */
class LanguageService implements Disposable {
    private readonly languages: Record<string, LanguageServiceProviderAbstract> = {};

    dispose(): any {
    }

    /**
     * 注册语言的服务
     * @param language 语言
     * @param service 服务
     */
    register(language: Languages, service: LanguageServiceProviderAbstract) {
        this.languages[language] = service;
    }

    /**
     * 将语言得目录都注册到 Context，所有语言注册后调用
     */
    registerContext() {
        commands.executeCommand(
            "setContext",
            "leetcode.dirs",
            Object.values(this.languages).map(provider => provider.dirPath())
        );
    }

    /**
     * 获取所有注册的语言
     */
    getLanguages(): string[] {
        return Object.keys(this.languages);
    }

    /**
     * 根据 fsPath 获取 Languages
     */
    getLanguagesByFsPath(fsPath: string): Languages | undefined {
        for (let language of Object.keys(this.languages)) {
            console.log(language, fsPath);
            if (this.languages[language].filePath() === fsPath) {
                return strMapLanguages.get(language);
            }
        }
    }

    private async checkConfig(): Promise<LanguageServiceProviderAbstract> {
        let workPath = configurationUtil.get(ConfigurationEnum.workPath);
        if (!workPath) {
            return Promise.reject(ERRORS.pleaseSelectWorkPath);
        }
        const language = configurationUtil.get(ConfigurationEnum.languages) ||
            await window.showQuickPick(this.getLanguages()).then(v => {
                if (v) {
                    return configurationUtil.update(ConfigurationEnum.languages, v).then(() => v);
                }
                return v;
            });
        if (!language) {
            return Promise.reject(ERRORS.pleaseSelectTheDefaultLanguage);
        }
        return this.languages[language];
    }

    openEditor(question: QuestionData): Promise<void> {
        return this.checkConfig().then(provider => {
            const questionId = question.data.question.questionId;
            const questionFilePath = path.join(configurationUtil.get(ConfigurationEnum.workPath) as string, "questions", `${questionId}.json`);
            fs.createFileSync(questionFilePath);
            fs.writeFileSync(questionFilePath, JSON.stringify(question));
            return provider.openEditor(question);
        });
    }

    /**
     * 获取提交或者测试需要的数据
     */
    getTestOrSubmitQuestionData(language: Languages): Promise<TestOrSubmitQuestionData> {
        const ls = this.languages[language];
        if (!ls) {
            return Promise.reject("不支持的语言" + language);
        }
        return ls.getQuestionData().then(base => {
            const questionFilePath = path.join(configurationUtil.get(ConfigurationEnum.workPath) as string, "questions", `${base.id}.json`);
            const data: QuestionData = JSON.parse(fs.readFileSync(questionFilePath).toString());
            const {titleSlug, judgeType} = data.data.question;
            return {
                titleSlug,
                judgeType,
                ...base
            };
        });
    }
}

export const languageService = new LanguageService();

/**
 * 提交或者测试需要的数据
 */
export type TestOrSubmitQuestionData = {
    code: string,
    id: number,
    testCase: string,
    titleSlug: string,
    judgeType: string
};